package com.swdegao.iot.netty.server.channelhandler;


import com.alibaba.fastjson.JSON;
import com.swdegao.iot.SwdegaoIotMgtServerApplication;
import com.swdegao.iot.netty.entity.*;
import com.swdegao.iot.netty.utils.ConvertUtils;
import com.swdegao.iot.netty.utils.RedisUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 用于存储数据包、更新redis中数据
 * @Author:只会走路的小鸟
 * @Date: Created in 8:20 2018\10\26 0001
 */
public class SaveMessgaeHandler extends SimpleChannelInboundHandler<HandlerMessage> {

	@Autowired
    private RedisUtils redisUtils = SwdegaoIotMgtServerApplication.getBean(RedisUtils.class);
	//定义一个全局的记录器，通过LoggerFactory获取
    private final static Logger logger = LoggerFactory.getLogger(SaveMessgaeHandler.class);

	@Override
	protected void channelRead0(ChannelHandlerContext cxt, HandlerMessage msg) throws Exception {
		String imei = msg.getImei();
		CallBackData callBackData = new CallBackData();
		try {

			Byte actiontype = msg.getActionTpye();

			UpData upData = new UpData();
			long nowtime = System.currentTimeMillis();
			upData.setCreatetime(nowtime);
			upData.setImei(imei);
			upData.setActionTpye(actiontype);

		    byte[] receiveMsgBytes = new byte[msg.getRecevieMsg().capacity()];
		    msg.getRecevieMsg().getBytes(msg.getRecevieMsg().readerIndex(), receiveMsgBytes);

		    upData.setUpData(Hex.encodeHexString(receiveMsgBytes));

			String callbackUrl = "";
			String topic = "";
			String tag = "";
			//imei信息以hash形式存储（key,hashkey,value）
			try {
				if(redisUtils.hmhave(Parameter.imei_info,imei)){//已经存储
					//logger.info(imei+"#######--开始");
					ImeiInfo imeiInfo = JSON.parseObject(redisUtils.hmGet(Parameter.imei_info,imei).toString(), ImeiInfo.class);
					msg.setApplicationSubscribe(imeiInfo.getApplicationSubscribe());//订阅的信息
					callbackUrl = (imeiInfo.getApplicationSubscribe()!=null&&imeiInfo.getApplicationSubscribe().size()>0) ? imeiInfo.getApplicationSubscribe().get(0).getCallbackurl().toString() : "";
					//2022-02-10 topic赋值
					topic = (imeiInfo.getApplication()!=null&&imeiInfo.getApplication().getTopicName()!=null) ? imeiInfo.getApplication().getTopicName().toString() : "";
					//tag = (imeiInfo.getApplicationSubscribe()!=null&&imeiInfo.getApplicationSubscribe().size()>0) ? imeiInfo.getApplicationSubscribe().get(0).getTag().toString() : "";
					//logger.info(imei+"#######--进入if");
					if(actiontype==(byte)0x81){
						//注册、更新时间、更新心跳周期
						int heartbeat_cycle = 0;
						try {
							heartbeat_cycle = receiveMsgBytes[0];
						} catch (Exception e) {
							// TODO: handle exception
							heartbeat_cycle = Parameter.heartbeat_cycle;
						}
						int heartbeat_registered_num = imeiInfo.getHeartbeat_registered_num();
						heartbeat_registered_num++;
						imeiInfo.setOnlineLastTime(nowtime);
						imeiInfo.setHeartbeat_registered_num(heartbeat_registered_num);
						imeiInfo.setHeartbeat_cycle(heartbeat_cycle);
						imeiInfo.setOnlineStatus("1");
						imeiInfo.setcType(Parameter.communication_tcp);
						redisUtils.hmSet(Parameter.imei_info, imei, JSON.toJSONString(imeiInfo));
					}
					//logger.info(imei+"#######--81结束进入83");
					if(actiontype==(byte)0x83){
						//判断问题是否失效
						String downDataId  = imeiInfo.getDownDataId();

						if(null!=downDataId && !"".equals(downDataId)){
							int OutTime = 0;
							try {
								OutTime = imeiInfo.getOutTime();
							} catch (Exception e) {
								// TODO: handle exception
								OutTime = Parameter.outtime_hear;
							}
							Long differenceTime = (nowtime - imeiInfo.getRequestLastTime())/1000 - OutTime;
							if(differenceTime>0){//问题已经过期、将hash中Imei_info更新、下次无需再验证问题失效逻辑
								imeiInfo.setDownDataId("");
								imeiInfo.setRequestLastTime((long)0);
								redisUtils.hmSet(Parameter.imei_info, imei, JSON.toJSONString(imeiInfo));
							}else{//问题没有过期、在updata记录downDataId信息，且单独记录本问题回复答案
								upData.setDownDataId(imeiInfo.downDataId);
								msg.setDownDataId(imeiInfo.downDataId);
								//更新问题最后响应时间
								imeiInfo.setRequestLastTime(nowtime);
								redisUtils.hmSet(Parameter.imei_info, imei, JSON.toJSONString(imeiInfo));
								//存储问题答案
								redisUtils.lPush(imei+"_"+upData.getDownDataId()+ Parameter.imei_info_requestdata,JSON.toJSONString(upData));//存储所有updata数据
							}
						}
					}
					//logger.info(imei+"#######--83结束进入87");
					if(actiontype==(byte)0x87){
						try {
							//进入预置命令发送模式
							if(redisUtils.exists(imei+ Parameter.imei_waitingpresetcommand)){
								String presetCommand_flag = upData.getUpData();//获取预置命令处理阶段标识
								PresetCommand presetCommand = JSON.parseObject(redisUtils.index(imei+ Parameter.imei_waitingpresetcommand, 0).toString(), PresetCommand.class);
								//发送预置命令逻辑
								if(Parameter.imei_presetcommand_flag_start.equals(presetCommand_flag)){
									if(Parameter.presetCommandNum.equals(presetCommand.getNum())){
										//已经达到预置命令重发上线,删除imei_waitingpresetcommand，添加imei_presetcommand
										redisUtils.removeValue(imei+ Parameter.imei_waitingpresetcommand, 1, JSON.toJSONString(presetCommand));//删除imei_waitingpresetcommand
										presetCommand.setStatus(Parameter.imei_presetcommand_status_error);
										redisUtils.lPush(imei+ Parameter.imei_presetcommand, JSON.toJSONString(presetCommand));//添加到imei_presetcommand
										presetCommand = redisUtils.exists(imei+ Parameter.imei_waitingpresetcommand)?JSON.parseObject(redisUtils.index(imei+ Parameter.imei_waitingpresetcommand, 0).toString(), PresetCommand.class) : null;
									}

									//发送预置命令
									if(null != presetCommand){
										//没有达到预置命令重发上线,num+1
										presetCommand.setNum(Integer.parseInt(presetCommand.getNum())+1+"");
										presetCommand.setActiontime(nowtime);
										//Thread.sleep(10);
										cxt.writeAndFlush(GetPresetCommand(imei,presetCommand));
										redisUtils.set(imei+ Parameter.imei_waitingpresetcommand, 0, JSON.toJSONString(presetCommand));//更新imei_waitingpresetcommand

									}
								}

								//接受预置命令处理成功逻辑
								if(Parameter.imei_presetcommand_flag_ok.equals(presetCommand_flag)){
									//处理成功
									redisUtils.removeValue(imei+ Parameter.imei_waitingpresetcommand, 1, JSON.toJSONString(presetCommand));//删除imei_waitingpresetcommand
									presetCommand.setActiontime(nowtime);
									presetCommand.setStatus(Parameter.imei_presetcommand_status_ok);
									redisUtils.lPush(imei+ Parameter.imei_presetcommand, JSON.toJSONString(presetCommand));//添加到imei_presetcommand
								}
							}
						} catch (Exception e) {
							// TODO: handle exception
							logger.error(imei+"#######--预置命令"+e.getMessage());
						}

					}
				}else{
					//logger.info(imei+"#######--进入redisinfo");
					//直接往hash中添加
					ImeiInfo imeiInfo = new ImeiInfo();
					imeiInfo.setOnlineLastTime(nowtime);
					imeiInfo.setOnlineStatus("1");
					imeiInfo.setcType(Parameter.communication_tcp);
					imeiInfo.setImei(imei);
					imeiInfo.setOutTime(Parameter.outtime_hear);
					imeiInfo.setHeartbeat_registered_num(0);
					imeiInfo.setHeartbeat_delay_num(0);
					int heartbeat_cycle = 0;
					if(actiontype==(byte)0x81){
						try {
							heartbeat_cycle = receiveMsgBytes[0];
						} catch (Exception e) {
							// TODO: handle exception
							heartbeat_cycle = Parameter.heartbeat_cycle;
						}
						imeiInfo.setHeartbeat_cycle(heartbeat_cycle);
					}

					//msg.setApplicationSubscribe(imeiInfo.getApplicationSubscribe());
					redisUtils.hmSet(Parameter.imei_info, imei, JSON.toJSONString(imeiInfo));
				}

			} catch (Exception e) {
				// TODO: handle exception
				logger.error(imei+"#######--svae逻辑异常",e);
			}

//			try {
//				redisUtils.lPush(imei+ Parameter.imei_info_updata,JSON.toJSONString(upData));//存储所有updata数据
//			} catch (Exception e) {
//				// TODO: handle exception
//				logger.error(imei+"#######--redisupdata存储异常"+e.getMessage());
//			}

			//将推送数据存储到redis中
			try {
				//IC卡表对  receiveMsgBytes[4] == (byte)0x60 不做限制
				if ((actiontype == (byte) 0x83 || actiontype == (byte) 0x85) && receiveMsgBytes.length>5 ) {// 走推送的流程
				//if ((actiontype == (byte) 0x83 || actiontype == (byte) 0x85) && receiveMsgBytes.length>5 && receiveMsgBytes[4] == (byte)0x60) {// 走推送的流程
					//callbackUrl = "".equals(callbackUrl)?myProps.getMycallbackurl() : callbackUrl;
					//CallBackData callBackData = new CallBackData();
					callBackData.setImei(imei);
					callBackData.setCreatetime(nowtime);
					callBackData.setUrl(callbackUrl);
					callBackData.setCallbackNum(0);
					callBackData.setUpData(upData.getUpData());
					callBackData.setTopic(topic);
					callBackData.setTag(tag);
					//临时取消推送逻辑，放置下一个handle中处理
					//redisUtils.lPush(imei+Parameter.imei_callbackurl,JSON.toJSONString(callBackData));//存储所有updata数据
				}
			} catch (Exception e) {
				// TODO: handle exception
				logger.error(imei+"#######--回调"+e.getMessage());
			}

		} catch (Exception e) {
			// TODO: handle exception
			logger.error(imei+"#######--savehandle"+e.getMessage());
		}

	//将message继续往下传递
		cxt.fireChannelRead(callBackData);
	}

	@Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (7)
	    	Channel incoming = ctx.channel();
			logger.info("client "+incoming.remoteAddress()+"异常"+cause.getMessage());
	        // 当出现异常就关闭连接
	        cause.printStackTrace();
	        //ctx.close();
	    }
	/**
	 * 预置命令
	 * @param imei
	 * @param presetCommand
	 * @return
	 * @throws DecoderException
	 */
	public ByteBuf GetPresetCommand(String imei, PresetCommand presetCommand) throws DecoderException {
		byte[]  downData = Hex.decodeHex(presetCommand.getDownData());
		int msg_length = 22 + downData.length;
		int msg_length_h = msg_length/100;
		int msg_length_l = msg_length -(msg_length/100)*msg_length_h;
		byte[] msg = new byte[msg_length];
        msg[0] = (byte) 0x80;
        msg[1] = (byte)Integer.parseInt(msg_length_l+"", 16);
        msg[2] = (byte)Integer.parseInt(msg_length_h+"", 16);
        msg[3] = (byte) 0x87;
        byte[] temp = imei.getBytes();
        System.arraycopy(temp, 0, msg, 4, 15);//类型、imei
        System.arraycopy(downData, 0, msg, 19, downData.length);//类型、imei
        msg[msg_length-3] = ConvertUtils.getTotalForByte(msg);//校验和
        msg[msg_length-2] = 0x0d;
        msg[msg_length-1] = 0x0a;
		return  Unpooled.wrappedBuffer(msg);
	}

}
